//
//  BSSocket.m
//  BSProject
//
//  Created by nsm on 2019/8/1.
//  Copyright © 2019 beisheng. All rights reserved.
//

#import "BSSocket.h"
#import "BSSocketReceiver.h"
#import <GCDAsyncSocket.h>

// 单次连接超时时间
static const NSTimeInterval kConnectTimeout = 1.f;
// 最大重连次数, 默认5次
static const NSUInteger kMaximumReconnectCount = 4;

@interface BSSocket () <GCDAsyncSocketDelegate>
@property (nonatomic) uint16_t port;
@property (nonatomic, copy) NSString *host;
@property (nonatomic, strong) GCDAsyncSocket *socket;
@property (nonatomic) NSUInteger reconnectCount;
@property (nonatomic, strong) BSSocketReceiver *receiver;
@end

@implementation BSSocket
+ (instancetype)sharedInstance {
    static BSSocket *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [self new];
        [instance didInitialize];
    });
    return instance;
}

- (void)didInitialize {
    self.reconnectCount = 0;
}

#pragma mark - setter/getter
- (BSSocketReceiver *)receiver {
    if (!_receiver) {
        _receiver = BSSocketReceiver.new;
    }
    return _receiver;
}

#pragma mark - GCDAsyncSocketDelegate
// 连接成功
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
    !self.didConnectSuccess?:self.didConnectSuccess();
    self.reconnectCount = 0;
    [sock readDataWithTimeout:-1 tag:0];
}

// 数据已发送
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
    [sock readDataWithTimeout:-1 tag:0];
}

// 接收到数据
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    [self receive:data];
}

// 链接断开
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    !self.didDisconnect?:self.didDisconnect(err);
    
    if (err) [self reconnect];
}

#pragma mark - 业务
- (BOOL)connectHost:(NSString *)host onPort:(uint16_t)port {
    self.host = host;
    self.port = port;
    
    return [self connect];
}

- (BOOL)connect {
    [self close];
    NSError *error = nil;
    self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self
                                             delegateQueue:dispatch_get_main_queue()];
    BOOL isOk = [self.socket connectToHost:self.host
                                    onPort:self.port
                               withTimeout:3
                                     error:&error];
    if (error) !self.didConnectFailure?:self.didConnectFailure(error);
    return isOk;
}

- (void)reconnect {
    if (self.socket.isConnected) return;
    // 重连次数到达上限（重置一个周期）
    if (self.reconnectCount > kMaximumReconnectCount) self.reconnectCount = 0;
    self.reconnectCount++;
    // 连接超时,重新重连(时间间隔线性增长)
    NSTimeInterval delayInSeconds = kConnectTimeout*self.reconnectCount;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        // 重连回调
        !self.didReconnecting?:self.didReconnecting(self.reconnectCount);
        [self connect];
    });
}

- (void)send:(id)data {
    if (!data) return;
    
    if ([data isKindOfClass:NSString.class])
        data = [(NSString *)data dataUsingEncoding:NSUTF8StringEncoding];
    else if ([data isKindOfClass:NSData.class])
        data = (NSData *)data;

    if (!data) return;
    !self.didSendData?:self.didSendData(data);
    [self.socket writeData:data withTimeout:-1 tag:0];
}

- (void)receive:(id)data {
    [self.receiver didRecvData:data];
    !self.didReceiveData?:self.didReceiveData(data);
}

- (void)close {
    if (!self.socket) return;
    
    [self.socket disconnect];
    self.socket.delegate = nil;
    self.socket = nil;
}

@end
